/*
 * Copyright (c) 2015-2018 Sfkj Science And Technology Co.,Ltd.
 * All Rights Reserved.
 * This software is the confidential and proprietary information of
 * Sfkj Science And Technology Co.,Ltd.
 * ("Confidential Information").You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sfkj.
 */
package com.sfkj.walk.web;

import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import com.eaio.uuid.UUID;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.sfkj.walk.SystemException;
import com.sfkj.walk.aliyun.oss.AliyunOssService;
import com.sfkj.walk.aliyun.oss.UploadFile;
import com.sfkj.walk.api.note.CreateNoteCommand;
import com.sfkj.walk.api.query.activity.ActivityOneByPredicateQuery;
import com.sfkj.walk.query.activity.Activity;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.axonframework.common.IdentifierFactory;
import org.axonframework.domain.ImageUrl;
import org.axonframework.queryhandling.QueryGateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

import static com.sfkj.walk.axon.web.WebContants.MY_PREFIX;

@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
@RestController
public class UploadController {
    private static final String AVARAT = "avatar";
    private static final String NOTE = "note";
    private static final String ACTIVITY = "activity";

    private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss");

    private final AliyunOssService aliyunOssService;
    private final QueryGateway queryGateway;
    private final CommandGateway commandGateway;

    @PostMapping("/upload/" + AVARAT)
    public Map<String, String> uploadAvatar(String userId, MultipartFile file) {
        UploadFile uploadFile = new UploadFile();
        uploadFile.setOriginalFilename(file.getOriginalFilename());
        uploadFile.setContentType(file.getContentType());
        uploadFile.setSize(file.getSize());
        try {
            uploadFile.setBytes(file.getBytes());
            uploadFile.setInputStream(file.getInputStream());
        } catch (IOException e) {
            throw new SystemException("获取文件异常:" + Throwables.getRootCause(e).getMessage());
        }
        uploadFile.setFileName(uploadFile.generateFileType(new UUID().toString().replace("-", StringUtils.EMPTY)));
        uploadFile.setFullFileName(AVARAT + "/" + uploadFile.getFileName());
        uploadFile.putMetaData("userId", userId);

        aliyunOssService.upload(uploadFile);

        return ImmutableMap.of("url", uploadFile.getUrl());
    }

    @PostMapping("/upload/" + ACTIVITY)
    public Map<String, String> uploadActivity(String activityId, MultipartFile file) {
        UploadFile uploadFile = new UploadFile();
        uploadFile.setOriginalFilename(file.getOriginalFilename());
        uploadFile.setContentType(file.getContentType());
        uploadFile.setSize(file.getSize());
        try {
            uploadFile.setBytes(file.getBytes());
            uploadFile.setInputStream(file.getInputStream());
        } catch (IOException e) {
            throw new SystemException("获取文件异常:" + Throwables.getRootCause(e).getMessage());
        }
        uploadFile.setFileName(uploadFile.generateFileType(new UUID().toString().replace("-", StringUtils.EMPTY)));
        uploadFile.setFullFileName(ACTIVITY + "/" + uploadFile.getFileName());
        uploadFile.putMetaData("activityId", activityId);

        aliyunOssService.upload(uploadFile);

        return ImmutableMap.of("url", uploadFile.getUrl());
    }

    @PostMapping(MY_PREFIX + "/upload/" + NOTE)
    public Map<String, String> upload(String activityId, Long lastModified, MultipartFile file) {
        Activity activity = queryGateway.send(ActivityOneByPredicateQuery.buildById(activityId), Activity.class).getNow(null);
        Preconditions.checkState(Objects.nonNull(activity), "活动不存在");

        UploadFile uploadFile = new UploadFile();
        uploadFile.setOriginalFilename(file.getOriginalFilename());
        uploadFile.setContentType(file.getContentType());
        uploadFile.setSize(file.getSize());
        try {
            uploadFile.setBytes(file.getBytes());
            uploadFile.setInputStream(file.getInputStream());
        } catch (IOException e) {
            throw new SystemException("获取文件异常:" + Throwables.getRootCause(e).getMessage());
        }
        String noteId = IdentifierFactory.getInstance().generateIdentifier();
        uploadFile.setFileName(uploadFile.generateFileType(noteId));
        uploadFile.setFullFileName(NOTE + getDir() + "/" + uploadFile.getFileName());
        uploadFile.putMetaData("activityId", activityId);
        uploadFile.putMetaData("noteId", noteId);

        aliyunOssService.upload(uploadFile);

        Map<String, Object> properties = Maps.newHashMap();
        LocalDateTime time = LocalDateTime.now();
        try {
            Metadata metadata = JpegMetadataReader.readMetadata(file.getInputStream());
            for (Directory directory : metadata.getDirectories()) {
                for (Tag tag : directory.getTags()) {
                    properties.put(
                            tag.getTagName(),
                            ImmutableMap.of(
                                    "tagName", tag.getTagName(),
                                    "description", tag.getDescription(),
                                    "directoryName", tag.getDirectoryName()
                            )
                    );
                }
            }
            // 提取拍摄时间
            ExifSubIFDDirectory directory = metadata.getDirectory(ExifSubIFDDirectory.class);
            Date date = directory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
            if (Objects.nonNull(date)) {
                time = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
            } else {
                time = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastModified), ZoneId.systemDefault());
            }
        } catch (JpegProcessingException | IOException e) {
            log.error("提取图片元数据失败:" + Throwables.getRootCause(e).getMessage());
        }

        CreateNoteCommand command = new CreateNoteCommand();
        command.setId(noteId);
        command.setActivityId(activityId);
        command.setUrl(new ImageUrl(uploadFile.getUrl()));
        command.setTime(time);
        command.setProperties(properties);
        commandGateway.sendAndWait(command);

        return ImmutableMap.of("url", uploadFile.getUrl());
    }

    private String getDir() {
        Calendar calendar = Calendar.getInstance();
        return "/" + String.valueOf(calendar.get(Calendar.YEAR));
    }

}
